/*
  Copyright (C) 2011 Zhao Ming(zhao.ming29@gmail.com)

  All rights reserved.

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU Lesser General Public License version 2.1, as
  published by the Free Software Foundation.  This program is
  distributed in the hope that it will be useful, but WITHOUT ANY
  WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
  License for more details.

  You should have received a copy of the GNU Lesser General Public License
  along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include<stdio.h>
#include"GHGS.h"

GHGS::GHGS( int n, int delay[], int w[] )
{
	int i;
	N = n;	
	pos = 0;
	buf = new int[1<<n];
	D = new int[N];
	W = new int[N];
	
	for( i=0;i<N;i++ )
		D[i] = delay[i];
	for( i=0;i<N;i++ )
	{
		W[i] = w[i];
	}
	for( i=0;i<(1<<N);i++ )
		buf[i]=0;
}

void GHGS::reset()
{
	int i;
	for( i=0;i<(1<<N);i++ )
		buf[i]=0;
	pos = 0;
}

GHGS::~GHGS()
{
	delete buf;
	delete D;	
	delete W;
}

int GHGS::doit( int in, int& outP, int& outN )
{
	int mi,mo,bi,bo;

	mi = in;
	bi = in;
		
	int i;
	
	for( i=0;i<N;i++ )
	{
		mo = mi;
		bo = buf[ D[i] + (pos&(D[i]-1)) ];
		buf[ D[i] + (pos&(D[i]-1)) ] = bi;
		mi = mo + W[i]*bo;
		bi = mo - W[i]*bo;
	}
	pos++;
	outP = mi;
	outN = bi;
	return 0;			
}

void GHGS::genCode( char *code )
{
	int len = 1<<N;
	int i;
	int CP,CN;
	reset();
	doit(1,CP,CN);
	i = len - 1;
	code[i/8]&=~(1<<(i%8));
	CP = (1 - CP)/2;
	CP&=1;
	code[i/8]|=(CP<<(i%8));
	while( i>0 )
	{
		i--;
		doit(0,CP,CN);
		code[i/8]&=~(1<<(i%8));
		CP = (1 - CP)/2;
		CP&=1;
		code[i/8]|=(CP<<(i%8));
	}	
}	

#ifdef GHGSTEST
int main()
{
	int D[] = {64,   4,   8,   2,  16,   1,  32};
	int W[] = {-1,  -1,  -1,   1,   1,   1,   1};
	int *codeP = new int[128];
	int *codeN = new int[128];
	int *xcorr = new int[255];
	
	GHGS *aGHGS = new GHGS(7,D,W);
	
	int i,j,k;
	
	aGHGS->doit(1,codeP[127],codeN[127]);
	for( i=1;i<128;i++ )
	{
		aGHGS->doit(0,codeP[127-i],codeN[127-i]);
	}
	aGHGS->reset();
	printf("\n");
	for( i=0;i<128;i++ )
		if( codeP[i]==1 )
			printf("+");
		else
			if( codeP[i]==-1 )
				printf("-");
			else
				printf("*");
	printf("\n");					
	for( i=0;i<128;i++ )
	{
		aGHGS->doit(codeP[i],xcorr[i],codeN[0]);
	}
	for( i=128;i<255;i++ )
	{
		aGHGS->doit(0,xcorr[i],codeN[0]);
	}
	int max=0;
#define ABS(n) ( n>0 ? n:-n )
	for( i=0;i<255;i++ )
	{
		if( i!= 127 )
			if( ABS(xcorr[i])>max )
				max = ABS(xcorr[i]);	
	}
#undef ABS	
	printf(" Max xcorr is %d\n",max );
	aGHGS->reset();
	
	char code[16];
	aGHGS->genCode( code );
	for( i=0;i<128;i++ )
	if( ((code[i/8]>>(i%8))&1)==0 )
		printf("+");
	else
		printf("-");
	printf("\n");					

	aGHGS->reset();
	for( i=0;i<128;i++ )
	{
		int j = code[i/8]>>(i%8);
		j&=1;
		aGHGS->doit(1-2*j,xcorr[i],codeN[0]);
	}
	for( i=128;i<255;i++ )
	{
		aGHGS->doit(0,xcorr[i],codeN[0]);
	}
	max=0;
#define ABS(n) ( n>0 ? n:-n )
	for( i=0;i<255;i++ )
	{
		if( i!= 127 )
			if( ABS(xcorr[i])>max )
				max = ABS(xcorr[i]);	
	}
#undef ABS	
	printf(" Max xcorr is %d\n",max );
	return 0;	
}

#endif